<template>
  <div class="activities-page">
    <!-- 页面标题 -->
    <t-card class="header-card">
      <div class="card-header">
        <h2 class="page-title">活动管理</h2>
        <t-space>
          <t-button theme="primary" @click="handleCreateActivity">
            <template #icon><t-icon name="add" /></template>
            新增活动
          </t-button>
        </t-space>
      </div>
    </t-card>
    
    <!-- 搜索和筛选 -->
    <t-card class="filter-card">
      <t-form layout="inline" :data="searchForm" @reset="handleSearchReset" @submit="handleSearchSubmit">
        <t-form-item label="活动名称" name="keyword">
          <t-input
            v-model="searchForm.keyword"
            placeholder="请输入活动名称关键词"
            clearable
          />
        </t-form-item>
        <t-form-item label="分类" name="category">
          <t-select
            v-model="searchForm.category"
            placeholder="请选择分类"
            clearable
            style="width: 150px"
          >
            <t-option
              v-for="item in categoryOptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            />
          </t-select>
        </t-form-item>
        <t-form-item label="状态" name="status">
          <t-select
            v-model="searchForm.status"
            placeholder="请选择状态"
            clearable
            style="width: 150px"
          >
            <t-option
              v-for="item in statusOptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            />
          </t-select>
        </t-form-item>
        <t-form-item>
          <t-space>
            <t-button theme="primary" type="submit">
              <template #icon><t-icon name="search" /></template>
              搜索
            </t-button>
            <t-button theme="default" type="reset">重置</t-button>
          </t-space>
        </t-form-item>
      </t-form>
    </t-card>
    
    <!-- 活动列表表格 -->
    <t-card class="table-card">
      <t-table
        :data="activityList"
        :columns="columns"
        :row-key="rowKey"
        :loading="tableLoading"
        :pagination="pagination"
        :hover="true"
        @page-change="onPageChange"
      >
        <!-- 标题列 -->
        <template #title="{ row }">
          <div class="activity-title">
            {{ row.title }}
          </div>
        </template>
        
        <!-- 海报列 -->
        <template #posterUrl="{ row }">
          <div class="poster-thumbnail">
            <t-image
              :src="row.posterUrl"
              :style="{ width: '60px', height: '60px', objectFit: 'cover' }"
              fit="cover"
              shape="round"
            />
          </div>
        </template>
        
        <!-- 分类列 -->
        <template #category="{ row }">
          <t-tag theme="default" variant="light">{{ getCategoryLabel(row.category) }}</t-tag>
        </template>
        
        <!-- 状态列 -->
        <template #status="{ row }">
          <t-tag :theme="getStatusTheme(row.status)">
            {{ getStatusLabel(row.status) }}
          </t-tag>
        </template>
        
        <!-- 时间列 -->
        <template #time="{ row }">
          <div class="activity-time">
            <div>开始：{{ formatDate(row.startTime) }}</div>
            <div>结束：{{ formatDate(row.endTime) }}</div>
          </div>
        </template>

        <!-- 报名信息列 -->
        <template #participants="{ row }">
          {{ row.signupCount || 0 }}/{{ row.maxParticipants }}
        </template>
        
        <!-- 操作列 -->
        <template #operation="{ row }">
          <t-space>
            <t-link theme="primary" hover="color" @click="handleEditActivity(row)">编辑</t-link>
            <t-link theme="primary" hover="color" @click="handlePreviewActivity(row)">预览</t-link>
            <t-link
              theme="primary"
              hover="color"
              @click="handleToggleStatus(row)"
            >
              {{ getNextStatusActionName(row.status) }}
            </t-link>
            <t-link
              v-if="canCancelActivity(row)"
              theme="warning"
              hover="color"
              @click="handleCancelActivity(row)"
            >
              取消活动
            </t-link>
            <t-link
              theme="primary"
              hover="color"
              @click="handleViewSignups(row)"
            >
              查看报名
            </t-link>
            <t-popconfirm
              content="确认删除该活动吗？该操作不可撤销。"
              @confirm="handleDeleteActivity(row)"
            >
              <t-link theme="danger" hover="color">删除</t-link>
            </t-popconfirm>
          </t-space>
        </template>
      </t-table>
    </t-card>
    
    <!-- 活动表单对话框 -->
    <t-dialog
      v-model:visible="dialogVisible"
      :header="formMode === 'create' ? '新增活动' : '编辑活动'"
      width="800px"
      :footer="false"
      @close="resetForm"
    >
      <t-steps theme="primary" :current="currentStep" :style="{ marginBottom: '24px' }">
        <t-step-item title="基本信息" />
        <t-step-item title="时间地点" />
        <t-step-item title="价格与名额" />
        <t-step-item title="发布设置" />
      </t-steps>

      <t-form
        ref="form"
        :data="formData"
        :rules="rules[currentStep]"
        :label-width="100"
      >
        <!-- 步骤1：基本信息 -->
        <div v-show="currentStep === 0">
          <t-form-item label="活动标题" name="title">
            <t-input v-model="formData.title" placeholder="请输入活动标题" />
          </t-form-item>
          <t-form-item label="活动分类" name="category">
            <t-select
              v-model="formData.category"
              placeholder="请选择活动分类"
              clearable
            >
              <t-option
                v-for="item in categoryOptions"
                :key="item.value"
                :label="item.label"
                :value="item.value"
              />
            </t-select>
          </t-form-item>
          <t-form-item label="活动海报" name="posterUrl">
            <t-upload
              v-model="formData.posterUrl"
              theme="image"
              accept="image/*"
              :action="uploadAction"
              :before-upload="handleBeforeUpload"
              :max="1"
              :format-response="formatUploadResponse"
            >
              <template #tip>
                <p class="upload-tip">支持.jpg .jpeg .png格式，大小不超过2M</p>
              </template>
            </t-upload>
          </t-form-item>
          <t-form-item label="活动标签" name="tags">
            <t-input-tag v-model="formData.tags" placeholder="输入标签后按回车添加" clearable />
          </t-form-item>
          <t-form-item label="活动描述" name="description">
            <t-textarea
              v-model="formData.description"
              placeholder="请输入活动详细描述"
              :autosize="{ minRows: 4, maxRows: 8 }"
            />
          </t-form-item>
        </div>

        <!-- 步骤2：时间地点 -->
        <div v-show="currentStep === 1">
          <t-form-item label="活动时间" name="timeRange">
            <t-date-range-picker
              v-model="timeRange"
              enable-time-picker
              placeholder="请选择活动开始和结束时间"
              @change="handleTimeRangeChange"
            />
          </t-form-item>
          <t-form-item label="活动地点" name="location">
            <t-input v-model="formData.location" placeholder="请输入活动地点" />
          </t-form-item>
          <t-form-item label="联系电话" name="contactPhone">
            <t-input v-model="formData.contactPhone" placeholder="请输入联系电话" />
          </t-form-item>
        </div>

        <!-- 步骤3：价格与名额 -->
        <div v-show="currentStep === 2">
          <t-form-item label="活动价格" name="price">
            <t-input-number v-model="formData.price" placeholder="请输入活动价格" step="10" min="0" />
          </t-form-item>
          <t-form-item label="参与人数" name="maxParticipants">
            <t-input-number v-model="formData.maxParticipants" placeholder="请输入最大参与人数" step="1" min="1" />
          </t-form-item>
        </div>

        <!-- 步骤4：发布设置 -->
        <div v-show="currentStep === 3">
          <t-form-item label="活动状态" name="status">
            <t-radio-group v-model="formData.status">
              <t-radio value="upcoming">待开始</t-radio>
              <t-radio value="registering">报名中</t-radio>
              <t-radio value="ongoing">进行中</t-radio>
              <t-radio value="completed">已结束</t-radio>
            </t-radio-group>
          </t-form-item>
        </div>

        <!-- 表单按钮 -->
        <t-form-item>
          <t-space>
            <t-button theme="default" @click="dialogVisible = false">取消</t-button>
            <t-button v-if="currentStep > 0" theme="default" @click="prevStep">上一步</t-button>
            <t-button v-if="currentStep < 3" theme="primary" @click="nextStep">下一步</t-button>
            <t-button v-if="currentStep === 3" theme="primary" @click="handleFormSubmit" :loading="submitLoading">确定</t-button>
          </t-space>
        </t-form-item>
      </t-form>
    </t-dialog>
    
    <!-- 活动预览对话框 -->
    <t-dialog
      v-model:visible="previewVisible"
      header="活动预览"
      width="800px"
      :footer="false"
    >
      <div class="activity-preview" v-if="previewData">
        <h1 class="preview-title">{{ previewData.title }}</h1>
        <div class="preview-meta">
          <t-tag theme="default" variant="light">{{ getCategoryLabel(previewData.category) }}</t-tag>
          <t-tag :theme="getStatusTheme(previewData.status)">{{ getStatusLabel(previewData.status) }}</t-tag>
        </div>
        <div class="preview-poster" v-if="previewData.posterUrl">
          <t-image :src="previewData.posterUrl" fit="contain" :style="{ maxHeight: '300px' }" />
        </div>
        <div class="preview-info">
          <div class="info-item">
            <i class="t-icon t-icon-time"></i>
            <span>{{ formatDate(previewData.startTime) }} - {{ formatDate(previewData.endTime) }}</span>
          </div>
          <div class="info-item">
            <i class="t-icon t-icon-location"></i>
            <span>{{ previewData.location }}</span>
          </div>
          <div class="info-item">
            <i class="t-icon t-icon-user-circle"></i>
            <span>名额：{{ previewData.signupCount || 0 }}/{{ previewData.maxParticipants }}</span>
          </div>
          <div class="info-item">
            <i class="t-icon t-icon-money-circle"></i>
            <span>价格：¥{{ previewData.price }}</span>
          </div>
          <div class="info-item">
            <i class="t-icon t-icon-call"></i>
            <span>联系电话：{{ previewData.contactPhone }}</span>
          </div>
        </div>
        <div class="preview-tags" v-if="previewData.tags && previewData.tags.length">
          <t-tag v-for="(tag, index) in previewData.tags" :key="index" theme="primary" variant="light" :style="{ margin: '0 4px 4px 0' }">
            {{ tag }}
          </t-tag>
        </div>
        <div class="preview-description">
          <h3>活动描述</h3>
          <div class="description-content">{{ previewData.description }}</div>
        </div>
      </div>
    </t-dialog>

    <!-- 报名信息对话框 -->
    <t-dialog
      v-model:visible="signupVisible"
      header="报名信息"
      width="800px"
      :footer="false"
    >
      <t-table
        :data="signupList"
        :columns="signupColumns"
        :loading="signupLoading"
        :hover="true"
      >
        <!-- 支付状态列 -->
        <template #payStatus="{ row }">
          <t-tag :theme="row.payStatus === 'paid' ? 'success' : 'warning'">
            {{ row.payStatus === 'paid' ? '已支付' : '待支付' }}
          </t-tag>
        </template>
        <!-- 操作列 -->
        <template #operation="{ row }">
          <t-space>
            <t-popconfirm
              content="确认取消该用户的报名吗？"
              @confirm="handleCancelSignup(row)"
            >
              <t-link theme="danger" hover="color">取消报名</t-link>
            </t-popconfirm>
          </t-space>
        </template>
      </t-table>
    </t-dialog>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, computed, onMounted } from 'vue'
import { MessagePlugin } from 'tdesign-vue-next'
import type { PrimaryTableCol, TableRowData, PageInfo } from 'tdesign-vue-next'
import {
  getActivities,
  getActivityDetail,
  createActivity,
  updateActivity,
  deleteActivity,
  updateActivityStatus,
  cancelActivity,
  getActivitySignups,
  cancelSignup,
  uploadActivityPoster,
  type Activity,
  type ActivityFormData,
  type SignupInfo
} from '../../api/content/activities'

// 表格列定义
const columns: PrimaryTableCol[] = [
  {
    colKey: 'title',
    title: '活动名称',
    width: 200,
    cell: 'title'
  },
  {
    colKey: 'posterUrl',
    title: '海报',
    width: 100,
    cell: 'posterUrl'
  },
  {
    colKey: 'category',
    title: '分类',
    width: 100,
    cell: 'category'
  },
  {
    colKey: 'time',
    title: '活动时间',
    width: 180,
    cell: 'time'
  },
  {
    colKey: 'participants',
    title: '报名/名额',
    width: 100,
    cell: 'participants'
  },
  {
    colKey: 'status',
    title: '状态',
    width: 100,
    cell: 'status'
  },
  {
    colKey: 'operation',
    title: '操作',
    fixed: 'right',
    width: 280,
    cell: 'operation'
  }
]

// 报名表格列定义
const signupColumns: PrimaryTableCol[] = [
  { colKey: 'name', title: '姓名', width: 100 },
  { colKey: 'gender', title: '性别', width: 80 },
  { colKey: 'phone', title: '电话', width: 140 },
  { colKey: 'idCard', title: '身份证', width: 180 },
  { colKey: 'signupTime', title: '报名时间', width: 160 },
  { colKey: 'payStatus', title: '支付状态', width: 100, cell: 'payStatus' },
  { colKey: 'remark', title: '备注', width: 200 },
  { colKey: 'operation', title: '操作', width: 100, cell: 'operation' }
]

// 表格数据
const activityList = ref<Activity[]>([])
const tableLoading = ref(false)
const rowKey = 'id'

// 报名数据
const signupList = ref<SignupInfo[]>([])
const signupLoading = ref(false)
const signupVisible = ref(false)
const currentActivityId = ref('')

// 分页配置
const pagination = reactive({
  current: 1,
  pageSize: 10,
  total: 0
})

// 搜索表单
const searchForm = reactive({
  keyword: '',
  category: '',
  status: ''
})

// 活动分类选项
const categoryOptions = [
  { value: 'culture', label: '文化活动' },
  { value: 'sport', label: '体育运动' },
  { value: 'health', label: '健康养生' },
  { value: 'travel', label: '旅游出行' },
  { value: 'lecture', label: '讲座沙龙' },
  { value: 'other', label: '其他' }
]

// 活动状态选项
const statusOptions = [
  { value: 'upcoming', label: '待开始' },
  { value: 'registering', label: '报名中' },
  { value: 'ongoing', label: '进行中' },
  { value: 'completed', label: '已结束' },
  { value: 'canceled', label: '已取消' }
]

// 表单数据
const formMode = ref<'create' | 'edit'>('create')
const dialogVisible = ref(false)
const submitLoading = ref(false)
const form = ref(null)
const currentStep = ref(0)
const timeRange = ref<[Date, Date] | null>(null)

// 表单初始化数据
const defaultFormData: ActivityFormData = {
  title: '',
  posterUrl: '',
  category: '',
  startTime: '',
  endTime: '',
  location: '',
  maxParticipants: 20,
  description: '',
  tags: [],
  price: 0,
  contactPhone: '',
  status: 'upcoming'
}

// 表单数据
const formData = reactive<ActivityFormData>({ ...defaultFormData })

// 表单验证规则
const rules = [
  {
    // 步骤1验证规则
    title: [{ required: true, message: '请输入活动标题', type: 'error' }],
    category: [{ required: true, message: '请选择活动分类', type: 'error' }],
    posterUrl: [{ required: true, message: '请上传活动海报', type: 'error' }],
    description: [{ required: true, message: '请输入活动描述', type: 'error' }]
  },
  {
    // 步骤2验证规则
    timeRange: [{ required: true, message: '请选择活动时间', type: 'error' }],
    location: [{ required: true, message: '请输入活动地点', type: 'error' }],
    contactPhone: [{ required: true, message: '请输入联系电话', type: 'error' }]
  },
  {
    // 步骤3验证规则
    price: [{ required: true, message: '请输入活动价格', type: 'error' }],
    maxParticipants: [{ required: true, message: '请输入最大参与人数', type: 'error' }]
  },
  {
    // 步骤4验证规则
    status: [{ required: true, message: '请选择活动状态', type: 'error' }]
  }
]

// 预览数据
const previewVisible = ref(false)
const previewData = ref<Activity | null>(null)

// 上传配置
const uploadAction = '/api/upload/activity'

// 初始化数据
onMounted(() => {
  fetchActivityList()
})

// 获取活动列表
const fetchActivityList = async () => {
  tableLoading.value = true
  try {
    const { data } = await getActivities({
      page: pagination.current,
      pageSize: pagination.pageSize,
      keyword: searchForm.keyword || undefined,
      category: searchForm.category || undefined,
      status: searchForm.status || undefined
    })
    
    // 模拟数据
    activityList.value = data || []
    pagination.total = data?.length || 0
  } catch (error) {
    console.error('获取活动列表失败', error)
    MessagePlugin.error('获取活动列表失败')
  } finally {
    tableLoading.value = false
  }
}

// 格式化日期
const formatDate = (dateStr: string) => {
  if (!dateStr) return '-'
  const date = new Date(dateStr)
  return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')} ${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`
}

// 获取分类标签
const getCategoryLabel = (value: string) => {
  const category = categoryOptions.find(item => item.value === value)
  return category ? category.label : value
}

// 获取状态标签
const getStatusLabel = (status: Activity['status']) => {
  const statusMap: Record<Activity['status'], string> = {
    upcoming: '待开始',
    registering: '报名中',
    ongoing: '进行中',
    completed: '已结束',
    canceled: '已取消'
  }
  return statusMap[status] || status
}

// 获取状态主题色
const getStatusTheme = (status: Activity['status']) => {
  const themeMap: Record<Activity['status'], 'default' | 'primary' | 'warning' | 'success' | 'danger'> = {
    upcoming: 'default',
    registering: 'primary',
    ongoing: 'success',
    completed: 'default',
    canceled: 'danger'
  }
  return themeMap[status] || 'default'
}

// 获取下一个状态操作名称
const getNextStatusActionName = (status: Activity['status']) => {
  const actionMap: Record<Activity['status'], string> = {
    upcoming: '开始报名',
    registering: '开始活动',
    ongoing: '结束活动',
    completed: '-',
    canceled: '-'
  }
  return actionMap[status] || '-'
}

// 判断是否可以取消活动
const canCancelActivity = (activity: Activity) => {
  return ['upcoming', 'registering'].includes(activity.status)
}

// 分页变化
const onPageChange = (pageInfo: PageInfo) => {
  pagination.current = pageInfo.current
  pagination.pageSize = pageInfo.pageSize
  fetchActivityList()
}

// 搜索表单提交
const handleSearchSubmit = () => {
  pagination.current = 1
  fetchActivityList()
}

// 搜索表单重置
const handleSearchReset = () => {
  pagination.current = 1
  fetchActivityList()
}

// 创建活动
const handleCreateActivity = () => {
  formMode.value = 'create'
  Object.assign(formData, defaultFormData)
  timeRange.value = null
  currentStep.value = 0
  dialogVisible.value = true
}

// 编辑活动
const handleEditActivity = async (row: Activity) => {
  formMode.value = 'edit'
  currentStep.value = 0
  dialogVisible.value = true
  submitLoading.value = true
  
  try {
    const { data } = await getActivityDetail(row.id)
    if (data) {
      // 填充表单数据
      Object.assign(formData, data)
      
      // 设置时间范围
      if (data.startTime && data.endTime) {
        timeRange.value = [new Date(data.startTime), new Date(data.endTime)]
      }
    }
  } catch (error) {
    console.error('获取活动详情失败', error)
    MessagePlugin.error('获取活动详情失败')
    dialogVisible.value = false
  } finally {
    submitLoading.value = false
  }
}

// 预览活动
const handlePreviewActivity = async (row: Activity) => {
  try {
    const { data } = await getActivityDetail(row.id)
    if (data) {
      previewData.value = data
      previewVisible.value = true
    }
  } catch (error) {
    console.error('获取活动详情失败', error)
    MessagePlugin.error('获取活动详情失败')
  }
}

// 切换活动状态
const handleToggleStatus = async (row: Activity) => {
  try {
    let newStatus: Activity['status'] = 'upcoming'
    
    switch (row.status) {
      case 'upcoming':
        newStatus = 'registering'
        break
      case 'registering':
        newStatus = 'ongoing'
        break
      case 'ongoing':
        newStatus = 'completed'
        break
      default:
        return
    }
    
    await updateActivityStatus(row.id, newStatus)
    MessagePlugin.success('状态更新成功')
    fetchActivityList()
  } catch (error) {
    console.error('更新活动状态失败', error)
    MessagePlugin.error('更新活动状态失败')
  }
}

// 取消活动
const handleCancelActivity = async (row: Activity) => {
  try {
    await cancelActivity(row.id)
    MessagePlugin.success('活动已取消')
    fetchActivityList()
  } catch (error) {
    console.error('取消活动失败', error)
    MessagePlugin.error('取消活动失败')
  }
}

// 查看报名信息
const handleViewSignups = async (row: Activity) => {
  currentActivityId.value = row.id
  signupVisible.value = true
  signupLoading.value = true
  
  try {
    const { data } = await getActivitySignups(row.id)
    signupList.value = data || []
  } catch (error) {
    console.error('获取报名信息失败', error)
    MessagePlugin.error('获取报名信息失败')
  } finally {
    signupLoading.value = false
  }
}

// 取消用户报名
const handleCancelSignup = async (signup: SignupInfo) => {
  try {
    await cancelSignup(currentActivityId.value, signup.id)
    MessagePlugin.success('已取消该用户报名')
    // 重新获取报名列表
    const { data } = await getActivitySignups(currentActivityId.value)
    signupList.value = data || []
  } catch (error) {
    console.error('取消报名失败', error)
    MessagePlugin.error('取消报名失败')
  }
}

// 删除活动
const handleDeleteActivity = async (row: Activity) => {
  try {
    await deleteActivity(row.id)
    MessagePlugin.success('删除成功')
    fetchActivityList()
  } catch (error) {
    console.error('删除活动失败', error)
    MessagePlugin.error('删除活动失败')
  }
}

// 上一步
const prevStep = () => {
  if (currentStep.value > 0) {
    currentStep.value -= 1
  }
}

// 下一步
const nextStep = () => {
  if (currentStep.value < 3) {
    currentStep.value += 1
  }
}

// 处理时间范围变化
const handleTimeRangeChange = (val: [Date, Date] | null) => {
  if (val && val.length === 2) {
    formData.startTime = val[0].toISOString()
    formData.endTime = val[1].toISOString()
  }
}

// 上传前检查
const handleBeforeUpload = (file: File) => {
  const isImage = /image\/\w+/.test(file.type)
  const isLt2M = file.size / 1024 / 1024 < 2
  
  if (!isImage) {
    MessagePlugin.error('只能上传图片文件！')
    return false
  }
  
  if (!isLt2M) {
    MessagePlugin.error('图片大小不能超过2MB！')
    return false
  }
  
  return true
}

// 格式化上传响应
const formatUploadResponse = (res: any) => {
  if (res.code === 0 && res.data) {
    return res.data.url
  }
  return ''
}

// 提交表单
const handleFormSubmit = async () => {
  submitLoading.value = true
  try {
    if (formMode.value === 'create') {
      await createActivity(formData)
      MessagePlugin.success('创建成功')
    } else {
      await updateActivity(formData.id!, formData)
      MessagePlugin.success('更新成功')
    }
    dialogVisible.value = false
    fetchActivityList()
  } catch (error) {
    console.error('提交失败', error)
    MessagePlugin.error('提交失败')
  } finally {
    submitLoading.value = false
  }
}

// 重置表单
const resetForm = () => {
  Object.assign(formData, defaultFormData)
  timeRange.value = null
  currentStep.value = 0
}
</script>

<style scoped>
.activities-page {
  padding: 20px;
}

.header-card {
  margin-bottom: 20px;
}

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.page-title {
  margin: 0;
  font-size: 20px;
  font-weight: 500;
}

.filter-card {
  margin-bottom: 20px;
}

.table-card {
  margin-bottom: 20px;
}

.activity-title {
  font-weight: 500;
}

.activity-time {
  font-size: 13px;
  line-height: 1.4;
}

.upload-tip {
  margin-top: 8px;
  font-size: 12px;
  color: rgba(0, 0, 0, 0.4);
}

.activity-preview {
  padding: 0 16px;
}

.preview-title {
  margin-top: 0;
  margin-bottom: 16px;
  font-size: 24px;
  text-align: center;
}

.preview-meta {
  display: flex;
  justify-content: center;
  gap: 12px;
  margin-bottom: 20px;
}

.preview-poster {
  text-align: center;
  margin-bottom: 24px;
}

.preview-info {
  padding: 16px;
  background-color: rgba(0, 0, 0, 0.02);
  border-radius: 8px;
  margin-bottom: 24px;
}

.info-item {
  display: flex;
  align-items: center;
  margin-bottom: 12px;
}

.info-item i {
  margin-right: 8px;
  color: rgba(0, 0, 0, 0.4);
}

.preview-tags {
  margin-bottom: 24px;
}

.preview-description h3 {
  font-size: 16px;
  margin-bottom: 12px;
}

.description-content {
  white-space: pre-line;
  line-height: 1.6;
}
</style>